#include <iostream>
#ifndef _MSC_VER
#include <cxxabi.h>
#endif

using namespace std;
int g_constructCnt = 0;
int g_copyCOnstructCnt = 0;
int g_destructCnt = 0;

struct A{
    A(){
        cout << "Construct :" << ++g_constructCnt << endl;
    }

    A(const A & a)
    {
        cout << "Copy Construct:" << ++g_copyCOnstructCnt << endl;
    }

    ~A(){
        cout << "Destruct:" << ++ g_destructCnt << endl;
    }
};

A GetA()
{
    return A(); //编译器的优化：返回值优化将会把临时对象优化掉
}

template <typename T>
void f(T && param); //这里的T 的类型需要推导，所以 && 是一个 universal reference

template <typename T>
class Test{
    public:
    Test(Test &&rhs); //已经定义了一个特定的类型 没有类型判断 此时的&& 是一个右值引用
};

void fun(Test<int>&& param)  //已经定义了一个确定的类型，没有类型推断，&& 是一个右值引用
{
} //void initializeJSP(unknownType Experiment);  当传入一个未知类型时，编译器会提示错误  :variable or field 'fun' declared void


template<typename T>
void f(const T && param); //param 是一个右值引用类型， universal reference 仅仅在 T&& 下发生，任何的附加条件都会使之失效，而变成一个普通的右值引用


int main(void)
{
    //A&& a = GetA();


    int && var1 = 1; //var1 的类型是 int&& //所有的右值引用叠加到右值引用上仍然还是一个右值引用

    auto && var2 = var1; //var2 存在类型推导， 此处的 auto&& 最终会被推导为 int&  //所有的其它引用类型之间的叠加都将变成左值引用
    //std::move 可以将一个左值转换成右值
    cout << typeid(var1).name() << endl;
    cout << typeid(var2).name() << endl;
    A a;
    cout << typeid(A).name() << endl;

    char * name = abi::__cxa_demangle(typeid(A).name(), nullptr, nullptr, nullptr);
    cout << name << endl;
    free(name);
    return  0;
}


//常量左值引用是一个“万能”的引用类型，可以接收左值、右值 常量左值和常量右值。需要注意的是，普通的左值引用不能接受右值
